home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / video / xevil-1.000 / xevil-1 / intel.C < prev    next >
C/C++ Source or Header  |  1995-07-24  |  27KB  |  1,304 lines

  1. // "intel.C"
  2.  
  3. /*    Copyright (C) 1994  Steve Hardt
  4.  
  5.     This program is free software; you can redistribute it and/or modify
  6.     it under the terms of the GNU General Public License as published by
  7.     the Free Software Foundation; either version 1, or (at your option)
  8.     any later version.
  9.  
  10.     This program is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.     GNU General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU General Public License
  16.     along with this program; if not, write to the Free Software
  17.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  18.  
  19.     Steve Hardt 
  20.     hardts@athena.mit.edu hardts@media.mit.edu
  21.     hardts@r4002.3dem.bioch.bcm.tmc.edu
  22.     2043 McClendon
  23.     Houston, TX 77030
  24. */
  25.  
  26. #ifndef NO_PRAGMAS
  27. #pragma implementation "intel.h"
  28. #endif
  29.  
  30.  
  31. // Include Files
  32. extern "C" {
  33.   #include <string.h>
  34. }
  35.  
  36. #include "utils.h"
  37. #include "physical.h"
  38. #include "intel.h"
  39. #include "actual.h"
  40.  
  41.  
  42.  
  43. // Defines
  44. #define TARGET_RANGE 500
  45. #define REFLEXES_TIME 4
  46. #define FIGHT_RANGE 45  // [50-40]
  47. #define FIGHT_RANGE_2 (FIGHT_RANGE * FIGHT_RANGE)
  48. #define WANDER_WIDTH 1000
  49. #define WANDER_HEIGHT 600
  50. #define SHOT_CUTOFF 9
  51. #define LADDER_JUMP_TIME 4
  52. #define FTHROWER_RANGE_2 (90 * 90)
  53. #define HEALTH_ATTACK_PERCENT .1
  54. #define TRANSMOGIFIER_PERCENT .15
  55. #define MASTER_MIN_DIST 50
  56. #define MASTER_MIN_DIST_2 (MASTER_MIN_DIST * MASTER_MIN_DIST)
  57. #define MASTER_MAX_DIST 350 
  58. #define MASTER_MAX_DIST_2 (MASTER_MAX_DIST * MASTER_MAX_DIST)
  59. // Strategy change times for different strategies.
  60. #define TO_AWAY_TARGET_TIME 30
  61. #define TO_POS_TIME 100
  62. #define TO_MASTER_TIME 100
  63.  
  64.  
  65. const IntelOptions Intel::intelOptionsDefault = 
  66. {
  67.   True, // classFriends
  68.   False, // harmless
  69.   False, // psychotic
  70.   False, // ignoreItems
  71.   False, // ignoreLemmings
  72. };
  73.  
  74.  
  75.  
  76. Intel::Intel(WorldP w,LocatorP l,char *name,int lives,
  77.          const IntelOptions *ops,ITmask opMask)
  78. {
  79.   intelStatusChanged = True;
  80.   living = True;
  81.   world = w;
  82.   locator = l;
  83.  
  84.   intelOptions = intelOptionsDefault;
  85.   if (opMask & ITharmless)
  86.     intelOptions.harmless = ops->harmless;
  87.   if (opMask & ITclassFriends)
  88.     intelOptions.classFriends = ops->classFriends;
  89.   if (opMask & ITpsychotic)
  90.     intelOptions.psychotic = ops->psychotic;
  91.   if (opMask & ITignoreItems)
  92.     intelOptions.ignoreItems = ops->ignoreItems;
  93.   if (opMask & ITignoreLemmings)
  94.     intelOptions.ignoreLemmings = ops->ignoreLemmings;
  95.  
  96.   // intelStatus
  97.   strcpy(intelStatus.name,name);
  98.   intelStatus.classId = A_None;
  99.   strcpy(intelStatus.clas,"none");
  100.   intelStatus.health = 0;
  101.   intelStatus.mass = 0;
  102.   intelStatus.weaponClassId = A_None;
  103.   strcpy(intelStatus.weapon,"none");
  104.   intelStatus.weaponReady = False;
  105.   intelStatus.ammo = PH_AMMO_UNLIMITED;
  106.   intelStatus.itemClassId = A_None;
  107.   strcpy(intelStatus.item,"none");
  108.   if (lives != IT_INFINITE_LIVES)
  109.     intelStatus.lives = lives - 1; // One life is used for current life.  
  110.   else 
  111.     intelStatus.lives = IT_INFINITE_LIVES;
  112.   intelStatus.humanKills = 0;
  113.   intelStatus.enemyKills = 0;
  114.   intelStatus.soups = 0;
  115. }
  116.  
  117.  
  118.  
  119. Boolean Intel::is_human()
  120. {
  121.   return False;
  122. }
  123.  
  124.  
  125. Boolean Intel::is_enemy()
  126. {
  127.   return False;
  128. }
  129.  
  130.  
  131.  
  132. Boolean Intel::is_lemming_intel()
  133. {
  134.   return False;
  135. }
  136.  
  137.  
  138.  
  139. Boolean Intel::reincarnate_me()
  140. {
  141.   return !living && 
  142.     (intelStatus.lives == IT_INFINITE_LIVES || intelStatus.lives > 0);
  143. }
  144.  
  145.  
  146.  
  147. void Intel::add_human_kill()
  148. {
  149.   intelStatus.humanKills++; 
  150.   intelStatusChanged = True;
  151. }
  152.  
  153.  
  154.  
  155. void Intel::add_enemy_kill()
  156. {
  157.   intelStatus.enemyKills++; 
  158.   intelStatusChanged = True;
  159. }
  160.  
  161.  
  162.  
  163. void Intel::add_soup()
  164. {
  165.   intelStatus.soups++; 
  166.   intelStatusChanged = True;
  167. }
  168.  
  169.  
  170.  
  171. ITcommand Intel::dir_to_command(Dir dir)
  172. {
  173.   assert(dir == CO_air || dir >= CO_R);
  174.   ITcommand ret = IT_CENTER;
  175.   if (dir != CO_air)
  176.     ret = (ITcommand)((dir - CO_R) * 0.5 + IT_R);
  177.   
  178.   return ret;
  179. }
  180.  
  181.  
  182.  
  183. ITcommand Intel::dir_to_command_weapon(Dir dir)
  184. {
  185.   assert(dir == CO_air || dir >= CO_R);
  186.   ITcommand ret = IT_WEAPON_CENTER;
  187.   if (dir != CO_air)
  188.     ret = (ITcommand)((dir - CO_R) * 0.5 + IT_WEAPON_R);
  189.   
  190.   return ret;
  191. }
  192.  
  193.  
  194.  
  195. Dir Intel::command_weapon_to_dir_4(ITcommand command)
  196. {
  197.   switch (command) {
  198.   case IT_WEAPON_R:
  199.     return CO_R;
  200.   case IT_WEAPON_DN:
  201.     return CO_DN;
  202.   case IT_WEAPON_L:
  203.     return CO_L;
  204.   case IT_WEAPON_UP:
  205.     return CO_UP;
  206.   };
  207.   
  208.   return CO_air;
  209. }
  210.  
  211.  
  212.  
  213. Dir Intel::command_weapon_to_dir_8(ITcommand command)
  214. {
  215.   switch (command) {
  216.   case IT_WEAPON_R:
  217.     return CO_R;
  218.   case IT_WEAPON_DN_R:
  219.     return CO_DN_R;
  220.   case IT_WEAPON_DN:
  221.     return CO_DN;
  222.   case IT_WEAPON_DN_L:
  223.     return CO_DN_L;
  224.   case IT_WEAPON_L:
  225.     return CO_L;
  226.   case IT_WEAPON_UP_L:
  227.     return CO_UP_L;
  228.   case IT_WEAPON_UP:
  229.     return CO_UP;
  230.   case IT_WEAPON_UP_R:
  231.     return CO_UP_R;
  232.   };
  233.  
  234.   return CO_air;
  235. }
  236.  
  237.  
  238.  
  239.  
  240. ITcommand Intel::center_pos_to_command(const Pos &pos)
  241. {
  242.   if (pos.y > pos.x)
  243.     {
  244.       if (pos.y > -pos.x)
  245.     return IT_DN;
  246.       else 
  247.     return IT_L;
  248.     }
  249.   else
  250.     {
  251.       if (pos.y > -pos.x)
  252.     return IT_R;
  253.       else
  254.     return IT_UP;
  255.     }
  256. }
  257.  
  258.  
  259.  
  260. void Intel::die()
  261. {
  262.   intelStatus.health = -1;  
  263.   intelStatus.classId = A_None;
  264.   strcpy(intelStatus.clas,"tormented spirit");
  265.   intelStatus.mass = 0;
  266.   intelStatus.weaponClassId = A_None;
  267.   strcpy(intelStatus.weapon,"none");
  268.   intelStatus.weaponReady = False;
  269.   intelStatus.ammo = PH_AMMO_UNLIMITED;
  270.   intelStatus.itemClassId = A_None;
  271.   strcpy(intelStatus.item,"none");
  272.  
  273.   intelStatusChanged = True; 
  274.  
  275.   Id invalid;
  276.   id = invalid;
  277.   living = False;
  278. }
  279.  
  280.  
  281.  
  282. void Intel::reincarnate()
  283. {
  284.   if (intelStatus.lives != IT_INFINITE_LIVES)
  285.     {
  286.       assert (intelStatus.lives > 0);
  287.       intelStatus.lives--;
  288.       intelStatusChanged = True;
  289.     }
  290.   living = True;
  291. }
  292.  
  293.  
  294.  
  295. void Intel::clock(PhysicalP p)
  296. {
  297.   assert(intelStatus.lives == IT_INFINITE_LIVES || intelStatus.lives >= 0);
  298.   assert (p->get_id(id) == PH_NO_SIG);
  299.  
  300.   // classId, class
  301.   ClassId classId = p->get_class_id();
  302.   if (classId != intelStatus.classId)
  303.     {
  304.       intelStatus.classId = classId;
  305.       strcpy(intelStatus.clas,p->identify());
  306.       intelStatusChanged = True;
  307.     }
  308.  
  309.   // health
  310.   Health health = p->get_health();
  311.   if ((health >= 0) && (health != intelStatus.health))
  312.     {
  313.       intelStatus.health = health;
  314.       intelStatusChanged = True;
  315.     }
  316.   
  317.   // mass
  318.   Mass mass = p->get_mass();
  319.   if (mass != intelStatus.mass)
  320.     {
  321.       intelStatus.mass = mass;
  322.       intelStatusChanged = True;
  323.     }
  324.  
  325.  
  326.   if (p->is_user())
  327.     {
  328.       PhysicalP user = p;
  329.  
  330.       // weaponClassId, weapon
  331.       PhysicalP weapon = user->get_weapon_current();
  332.       ClassId weaponClassId = weapon ? weapon->get_class_id() : A_None;
  333.       if (intelStatus.weaponClassId != weaponClassId)
  334.     {
  335.       intelStatus.weaponClassId = weaponClassId;
  336.       strcpy(intelStatus.weapon,weapon ? weapon->identify() : "none");
  337.       intelStatusChanged = True;
  338.     }
  339.  
  340.       // weaponReady
  341.       Boolean weaponReady = weapon ? ((WeaponP)weapon)->ready() : 
  342.       (p->is_fighter() || (p->is_built_in() && p->ready()));
  343.       if (intelStatus.weaponReady != weaponReady)
  344.     {
  345.       intelStatus.weaponReady = weaponReady;
  346.       intelStatusChanged = True;
  347.     }
  348.  
  349.       // ammo
  350.       int ammo = weapon ? ((WeaponP)weapon)->get_ammo() : PH_AMMO_UNLIMITED;
  351.       if (intelStatus.ammo != ammo)
  352.     {
  353.       intelStatus.ammo = ammo;
  354.       intelStatusChanged = True;
  355.     }
  356.       
  357.       // itemClassId, item
  358.       PhysicalP item = user->get_item_current();
  359.       ClassId itemClassId = item ? item->get_class_id() : A_None;
  360.       if (intelStatus.itemClassId != itemClassId)
  361.     {
  362.       intelStatus.itemClassId = itemClassId;
  363.       strcpy(intelStatus.item,item ? item->identify() : "none");
  364.       intelStatusChanged = True;
  365.     }
  366.     }
  367.   else // Not User.
  368.     {
  369.       if (intelStatus.weaponClassId != A_None)
  370.     {
  371.       intelStatus.weaponClassId = A_None;
  372.       strcpy(intelStatus.weapon,"none");
  373.       intelStatusChanged = True;
  374.     }
  375.  
  376.       Boolean weaponReady = 
  377.     p->is_fighter() || (p->is_built_in() && p->ready());
  378.       if (intelStatus.weaponReady != weaponReady)
  379.     {
  380.       intelStatus.weaponReady = weaponReady;
  381.       intelStatusChanged = True;
  382.     }
  383.  
  384.       if (intelStatus.ammo != PH_AMMO_UNLIMITED)
  385.     {
  386.       intelStatus.ammo = PH_AMMO_UNLIMITED;
  387.       intelStatusChanged = True;
  388.     }
  389.  
  390.       if (p->is_suicide())
  391.     {
  392.       if (intelStatus.itemClassId != A_SuicideButton)
  393.         {
  394.           intelStatus.itemClassId = A_SuicideButton;
  395.           strcpy(intelStatus.item,"suicide button");
  396.           intelStatusChanged = True;
  397.         }
  398.     }
  399.       else if (intelStatus.itemClassId != A_None)
  400.     {
  401.       intelStatus.itemClassId = A_None;
  402.       strcpy(intelStatus.item,"none");
  403.       intelStatusChanged = True;
  404.     }
  405.     }
  406.  
  407.   // Kills does not depend on the physical.
  408. }
  409.  
  410.  
  411.  
  412. Human::Human(WorldP w,LocatorP l,char *name,int lives,ColorNum cNum) :
  413.        Intel(w,l,name,lives,NULL,ITnone)
  414. {
  415.   command = IT_NO_COMMAND;
  416.   colorNum = cNum;
  417. }
  418.  
  419.  
  420.  
  421. Boolean Human::is_human()
  422. {
  423.   return True;
  424. }
  425.  
  426.  
  427.  
  428. void Human::clock(PhysicalP p)
  429.   assert(alive());
  430.   p->set_command(command); 
  431.   command = IT_NO_COMMAND; 
  432.   Intel::clock(p);
  433. }
  434.  
  435.  
  436.  
  437. Machine::Machine(WorldP w,LocatorP l,char *name,const IntelOptions *ops,
  438.          ITmask opMask,IntelP master) 
  439. : Intel(w,l,name,1,ops,opMask)
  440. {
  441.   // strategyChange uses default initializer.
  442.   Timer mTimer(REFLEXES_TIME);
  443.   reflexes = mTimer;
  444.   Timer oTimer(LADDER_JUMP_TIME);
  445.   ladderJump = oTimer;
  446.   strategy = doNothing;
  447.   if (master)
  448.     {
  449.       masterIntelId = master->get_intel_id(); 
  450.       masterSet = True;
  451.     }
  452.   else
  453.     masterSet = False;
  454. }
  455.  
  456.  
  457.  
  458. IntelId Machine::get_master_intel_id()
  459. {
  460.   if (masterSet)
  461.     return masterIntelId;
  462.   else
  463.     {
  464.       IntelId invalid;
  465.       return invalid;
  466.     }
  467. }
  468.  
  469.  
  470.  
  471. void Machine::add_human_kill()
  472. {
  473.   if (masterSet)
  474.     {
  475.       LocatorP l = get_locator();
  476.       IntelP intel = l->lookup(masterIntelId);
  477.       if (intel)
  478.     {
  479.       intel->add_human_kill();
  480.       return;
  481.     }
  482.     }
  483.   Intel::add_human_kill();
  484. }
  485.  
  486.  
  487.  
  488. void Machine::add_enemy_kill()
  489. {
  490.   if (masterSet)
  491.     {
  492.       LocatorP l = get_locator();
  493.       IntelP intel = l->lookup(masterIntelId);
  494.       if (intel)
  495.     {
  496.       intel->add_enemy_kill();
  497.       return;
  498.     }
  499.     }
  500.   Intel::add_enemy_kill();
  501. }
  502.  
  503.  
  504.  
  505. void Machine::add_soup()
  506. {
  507.   assert(0);
  508. }
  509.  
  510.  
  511.  
  512. void Machine::clock(PhysicalP p)
  513. {
  514.   assert(alive() && p->is_creature());
  515.   const IntelOptions &ops = get_intel_options();
  516.   LocatorP locator = get_locator();
  517.   Boolean commandSet = False;
  518.   
  519.   if (reflexes.ready())
  520.     {
  521.       // Use MedKit.
  522.       if (!commandSet && 
  523.       p->is_user() && 
  524.       (p->get_health() < p->get_health_max()) && 
  525.       (has_item(p,A_MedKit)))
  526.     {
  527.       PhysicalP item = p->get_item_current();
  528.       if (item && (item->get_class_id() == A_MedKit))
  529.         p->set_command(IT_ITEM_USE);
  530.       else
  531.         p->set_command(IT_ITEM_CHANGE);
  532.       commandSet = True;
  533.     }
  534.       
  535.       // Use Transmogifier.
  536.       if (!commandSet && p->is_user() && 
  537.       (p->get_health() < TRANSMOGIFIER_PERCENT * p->get_health_max()) &&
  538.       (has_item(p,A_Transmogifier)))
  539.     {
  540.       PhysicalP item = p->get_item_current();
  541.       if (item && (item->get_class_id() == A_Transmogifier))
  542.         p->set_command(IT_ITEM_USE);
  543.       else
  544.         p->set_command(IT_ITEM_CHANGE);
  545.       commandSet = True;
  546.     }
  547.  
  548.       // Use Shield.
  549.       if (!commandSet && p->is_user() && p->is_moving() && has_shield(p))
  550.     {
  551.       PhysicalP protectionP = 
  552.         locator->lookup(((MovingP)p)->get_protection());
  553.       if (!protectionP)
  554.         {
  555.           PhysicalP item = p->get_item_current();
  556.           if (item && item->is_shield())
  557.         p->set_command(IT_ITEM_USE);
  558.           else
  559.         p->set_command(IT_ITEM_CHANGE);
  560.           commandSet = True;
  561.         }
  562.     }
  563.  
  564.       // Use Doppel.
  565.       if (!commandSet && p->is_user() && p->is_moving() && 
  566.       has_item(p,A_Doppel))
  567.     {
  568.       PhysicalP item = p->get_item_current();
  569.       if (item && item->get_class_id() == A_Doppel)
  570.         p->set_command(IT_ITEM_USE);
  571.       else
  572.         p->set_command(IT_ITEM_CHANGE);
  573.       commandSet = True;
  574.     }
  575.       
  576.  
  577.       PhysicalP target = NULL;
  578.       
  579.       // Make sure master is not to close or too far away.
  580.       PhysicalP masterP = NULL; // meaningful iff masterSet (may be NULL).
  581.       int master_dist_2; // meaningful iff (masterSet && masterP).
  582.       if (masterSet)
  583.     {
  584.       IntelP master = locator->lookup(masterIntelId);
  585.       if (master)
  586.         {
  587.           Id masterId = master->get_id();
  588.           masterP = locator->lookup(masterId);
  589.           PhysicalP p = locator->lookup(get_id());
  590.           if (masterP && p)
  591.         {
  592.           const Area &masterArea = masterP->get_area();
  593.           const Area &area = p->get_area();
  594.           Pos masterMiddle = masterArea.get_middle();
  595.           Pos middle = area.get_middle();
  596.           Size diff = masterMiddle - middle;
  597.           master_dist_2 = diff.abs_2();
  598.         }
  599.           else
  600.         masterP = NULL; // To show that master_dist_2 is invalid.
  601.         }
  602.     }
  603.  
  604.       // Wandering too far from the master.
  605.       if (masterSet && masterP && master_dist_2 > MASTER_MAX_DIST_2)
  606.     {
  607.       strategyChange.set(TO_MASTER_TIME);
  608.       strategy = toMaster;
  609.       // target = masterP;
  610.       targetId = masterP->get_id();
  611.     }
  612.  
  613.  
  614.       // New strategy.
  615.       // Make sure target is non-NULL for strategies that require it.
  616.       if (strategyChange.ready())
  617.     {
  618.       Boolean isEnemy;
  619.       target = new_target_id(isEnemy,p,masterP); // Sets targetId.
  620.       
  621.       if (target)
  622.         {
  623.           if (isEnemy)
  624.         {
  625.           if ((ops.psychotic ||
  626.                (((p->is_user() && (has_gun(p) || has_cutter(p))) ||
  627.              p->is_fighter() || 
  628.              p->is_built_in() ||
  629.              p->prickly()) &&
  630.             (p->get_health() > 
  631.              HEALTH_ATTACK_PERCENT * p->get_health_max()))) &&
  632.               !ops.harmless)
  633.             strategy = toTarget;
  634.           else
  635.             strategy = awayTarget;
  636.         }
  637.           else
  638.         strategy = toTarget;
  639.           strategyChange.set(TO_AWAY_TARGET_TIME);
  640.         }
  641.       else
  642.         strategy = doNothing;
  643.     }
  644.       else 
  645.     // Make sure that target still exists.
  646.     if (strategy == toTarget || strategy == awayTarget
  647.         || strategy == toMaster)
  648.       {
  649.         target = locator->lookup(targetId);
  650.         if (!target)
  651.           strategy = doNothing;
  652.       }
  653.  
  654.       // If no target, change strategy to toPos.
  655.       if (strategy == doNothing && !masterSet)
  656.     {
  657.       strategy = toPos;
  658.       strategyChange.set(TO_POS_TIME);
  659.       
  660.       const Area &area = p->get_area();
  661.       Pos middle = area.get_middle();
  662.       
  663.       targetPos.x = middle.x + Utils::choose(WANDER_WIDTH) - 
  664.         WANDER_WIDTH / 2;
  665.       targetPos.y = middle.y + Utils::choose(WANDER_HEIGHT) - 
  666.         WANDER_HEIGHT / 2;
  667.     }
  668.  
  669.       // If nothing better to do, go to master.
  670.       if (strategy == doNothing && masterSet && masterP)
  671.     {
  672.       strategy = toMaster;
  673.       strategyChange.set(1);
  674.       target = masterP;
  675.       targetId = masterP->get_id();
  676.     }
  677.       
  678.  
  679.       // Act on current strategy.
  680.       switch (strategy) {
  681.       case toPos:
  682.     if (!commandSet)
  683.       commandSet = move_pos(p,targetPos,ladderJump);
  684.     break;
  685.     
  686.       case toTarget:
  687.     {
  688.       assert(target);
  689.  
  690.       // Check is_creature so won't attack items.
  691.       if (!commandSet && !ops.harmless && target->is_creature())
  692.         commandSet = attack_target(p,target);
  693.       
  694.       if (!commandSet)
  695.         commandSet = move_target(p,target,ladderJump);
  696.     }
  697.     break;
  698.     
  699.       case awayTarget:
  700.     {
  701.       assert(target);
  702.  
  703.       const IntelOptions &ops = get_intel_options();
  704.       // Check is_creature so won't attack items.
  705.       if (!commandSet && !ops.harmless && target->is_creature())
  706.         commandSet = attack_target(p,target);
  707.  
  708.       if (!commandSet)
  709.         commandSet = away_target(p,target,ladderJump);
  710.     }
  711.     break;
  712.     
  713.       case toMaster:
  714.     assert(target);
  715.     if (!commandSet)
  716.       commandSet = move_target(p,target,ladderJump);
  717.     if (masterSet && masterP && master_dist_2 < MASTER_MIN_DIST_2)
  718.       strategyChange.set(1);
  719.     break;
  720.     
  721.       case doNothing:
  722.     if (!commandSet)
  723.       {
  724.         p->set_command(IT_CENTER);
  725.         commandSet = True;
  726.       }
  727.     break;
  728.       };
  729.  
  730.       reflexes.set();
  731.     }
  732.   
  733.   reflexes.clock();
  734.   strategyChange.clock();
  735.   ladderJump.clock();
  736.   Intel::clock(p);
  737. }
  738.  
  739.  
  740.  
  741. Boolean Machine::attack_target(PhysicalP p,PhysicalP target)
  742. {
  743.   // Fire a gun if available.
  744.   Boolean useGun = p->is_user() && has_gun(p);
  745.   if (useGun)
  746.     {
  747.       if (weapon_current_is_gun(p))
  748.     {
  749.       PhysicalP weapon = p->get_weapon_current();
  750.       if (weapon->ready())
  751.         {
  752.           const Area &area = p->get_area();
  753.           Pos pos = area.get_middle();
  754.           const Area &targetArea = target->get_area();
  755.           Pos targetPos = targetArea.get_middle();
  756.           
  757.           Size rel = targetPos - pos;
  758.           Boolean distOk = True;
  759.           
  760.           if (weapon->get_class_id() == A_FThrower)
  761.         distOk = rel.abs_2() < FTHROWER_RANGE_2;
  762.           
  763.           if (distOk)
  764.         {
  765.           Dir weaponDir = rel.get_dir();
  766.           
  767.           const Vel *unitVels = p->get_unit_vels();
  768.           float z = rel.cross(unitVels[weaponDir]);
  769.               
  770.           if (fabs(z) <= SHOT_CUTOFF)
  771.             {
  772.               p->set_command(dir_to_command_weapon(weaponDir));
  773.               return True;
  774.             }
  775.         }
  776.         }
  777.     }
  778.       else /* if (weapon_current_is_gun(p)) */
  779.     {
  780.       p->set_command(IT_WEAPON_CHANGE);
  781.       return True;
  782.     }
  783.     } /* if (useGun) */
  784.   
  785.   
  786.   // Use cutter if available.
  787.   Boolean useCutter = !useGun && p->is_user() && has_cutter(p);
  788.   if (useCutter)
  789.     {
  790.       if (!weapon_current_is_cutter(p))
  791.     {
  792.       p->set_command(IT_WEAPON_CHANGE);
  793.       return True;
  794.     }
  795.       // else move toward target.
  796.     }
  797.   
  798.  
  799.   // Use built in weapon if available.
  800.   Boolean useBuiltIn = !useGun && !useCutter && p->is_built_in();
  801.   if (useBuiltIn)
  802.     {
  803.       if (!p->get_weapon_current())
  804.     {
  805.       if (p->ready())
  806.         {
  807.           const Area &area = p->get_area();
  808.           Pos pos = area.get_middle();
  809.           const Area &targetArea = target->get_area();
  810.           Pos targetPos = targetArea.get_middle();
  811.           
  812.           Size rel = targetPos - pos;
  813.           Dir weaponDir = rel.get_dir();
  814.           const Vel *unitVels = p->get_unit_vels();
  815.           float z = rel.cross(unitVels[weaponDir]);
  816.               
  817.           if (fabs(z) <= SHOT_CUTOFF)
  818.         {
  819.           p->set_command(dir_to_command_weapon(weaponDir));
  820.           return True;
  821.         }
  822.         }
  823.     }
  824.       else
  825.     {
  826.       p->set_command(IT_WEAPON_CHANGE);
  827.       return True;
  828.     }
  829.     }
  830.  
  831.   
  832.   // Close range fighting
  833.   if (!useGun && !useCutter && !useBuiltIn && p->is_fighter())
  834.     {
  835.       if (!p->get_weapon_current())
  836.     {
  837.       const Area &area = p->get_area();
  838.       const Area &targetArea = target->get_area();
  839.       const Pos middle = area.get_middle();
  840.       const Pos targetMiddle = targetArea.get_middle();
  841.       
  842.       if (middle.distance_2(targetMiddle) <= FIGHT_RANGE_2)
  843.         {
  844.           //  Dir dirTo = area.dir_to(targetArea);
  845.           Size rel = targetMiddle - middle;
  846.           Dir dirTo = rel.get_dir();
  847.  
  848.           p->set_command(dir_to_command_weapon(dirTo));
  849.           return True;
  850.         }
  851.     }
  852.       else
  853.     {
  854.       p->set_command(IT_WEAPON_CHANGE);
  855.       return True;
  856.     }
  857.     }
  858.  
  859.  
  860.   return False;
  861. }
  862.  
  863.  
  864.  
  865.  
  866. Boolean Machine::move_target(PhysicalP physical,PhysicalP target,
  867.                  Timer &ladderJump)
  868. {
  869.   const Area &area = physical->get_area();
  870.   Dir toTarget = area.dir_to(target->get_area());
  871.   
  872.   return move_dir(physical,toTarget,ladderJump);
  873. }
  874.  
  875.  
  876.  
  877. Boolean Machine::away_target(PhysicalP physical,PhysicalP target,
  878.                  Timer &ladderJump)
  879. {
  880.   const Area &area = physical->get_area();
  881.   Dir awayTarget = Coord::dir_opposite(area.dir_to(target->get_area()));
  882.   
  883.   return move_dir(physical,awayTarget,ladderJump);
  884. }
  885.  
  886.  
  887.  
  888. Boolean Machine::move_pos(PhysicalP physical,const Pos &targetPos,
  889.               Timer &ladderJump)
  890. {
  891.   const Area &area = physical->get_area();
  892.   Dir toPos = area.dir_to(targetPos);
  893.  
  894.   return move_dir(physical,toPos,ladderJump);
  895. }
  896.  
  897.  
  898.  
  899. Boolean Machine::move_dir(PhysicalP physical,Dir dir,
  900.               Timer &ladderJump)
  901. {
  902.   assert(physical->is_creature());
  903.   CreatureP creature = (CreatureP) physical;
  904.   ITcommand command = IT_NO_COMMAND;
  905.   
  906.   if (creature->is_flying())
  907.     command = dir_to_command(dir);
  908.   else // Sticky, Walking, Grounded, Hopping
  909.     {
  910.       Stance stance = creature->get_stance();
  911.       Touching touching = creature->get_touching_area();
  912.       const Hanging &hanging = creature->get_hanging();
  913.       Boolean canClimb = creature->can_climb();
  914.       
  915.       switch (dir) {
  916.       case CO_R:
  917.     switch (stance) {
  918.     case CO_center:
  919.     case CO_dn:
  920.     case CO_l:
  921.     case CO_up:
  922.       if ((touching != CO_R) || creature->is_sticky())
  923.         command = IT_R;
  924.       break;
  925.     case CO_climb:
  926.       if ((touching != CO_R) || creature->is_sticky())
  927.         {
  928.           command = IT_UP_R;
  929.           ladderJump.set();
  930.         }
  931.       break;
  932.     };
  933.     break;
  934.     
  935.       case CO_DN_R:
  936.     if (canClimb && touching != CO_dn && ladderJump.ready())
  937.       {
  938.         command = IT_DN;
  939.         break;
  940.       }
  941.     switch (stance) {
  942.     case CO_center:
  943.     case CO_dn:
  944.     case CO_up:
  945.       command = IT_R;
  946.       break;
  947.     case CO_r:
  948.       command = IT_DN;
  949.       break;
  950.     case CO_l:
  951.       command = IT_DN_R;
  952.       break;
  953.     case CO_climb:
  954.       if (touching != CO_dn)
  955.         command = IT_DN;
  956.       else
  957.         {
  958.           command = IT_R;
  959.           ladderJump.set();
  960.         }
  961.       break;
  962.     }
  963.     break;
  964.     
  965.       case CO_DN:
  966.     switch (stance) {
  967.     case CO_r:
  968.     case CO_up:
  969.     case CO_l:
  970.     case CO_climb:
  971.       if ((touching != CO_dn) || canClimb ||
  972.           (hanging.corner == CO_dn_R) || (hanging.corner == CO_dn_L))
  973.         command = IT_DN;
  974.       break;
  975.     case CO_center:
  976.       if (canClimb)
  977.         command = IT_DN;
  978.       break;
  979.     }
  980.     break;
  981.     
  982.       case CO_DN_L:
  983.     if (canClimb && touching != CO_dn && ladderJump.ready())
  984.       {
  985.         command = IT_DN;
  986.         break;
  987.       }
  988.     switch (stance) {
  989.     case CO_center:
  990.     case CO_dn:
  991.     case CO_up:
  992.       command = IT_L;
  993.       break;
  994.     case CO_l:
  995.       command = IT_DN;
  996.       break;
  997.     case CO_r:
  998.       command = IT_DN_L;
  999.       break;
  1000.     case CO_climb:
  1001.       if (touching != CO_dn && ladderJump.ready())
  1002.         command = IT_DN;
  1003.       else
  1004.         {
  1005.           command = IT_L;
  1006.           ladderJump.set();
  1007.         }
  1008.       break;
  1009.     }
  1010.     break;
  1011.     
  1012.       case CO_L:
  1013.     switch (stance) {
  1014.     case CO_center:
  1015.     case CO_dn:
  1016.     case CO_r:
  1017.     case CO_up:
  1018.       if ((touching != CO_L) || (creature->is_sticky()))
  1019.         command = IT_L;
  1020.       break;
  1021.     case CO_climb:
  1022.       if ((touching != CO_L) || (creature->is_sticky()))
  1023.         {
  1024.           command = IT_UP_L;
  1025.           ladderJump.set();
  1026.         }
  1027.       break;
  1028.     };
  1029.     break;
  1030.     
  1031.       case CO_UP_L:
  1032.     if (canClimb && touching != CO_up && ladderJump.ready())
  1033.       {
  1034.         command = IT_UP;
  1035.         break;
  1036.       }
  1037.     switch (stance) {
  1038.     case CO_center:
  1039.     case CO_dn:
  1040.     case CO_up:
  1041.       command = IT_L;
  1042.       break;
  1043.     case CO_r:
  1044.       command = IT_UP;
  1045.       break;
  1046.     case CO_l:
  1047.       command = IT_UP_L;
  1048.       break;
  1049.     case CO_climb:
  1050.       if (touching != CO_up)
  1051.         command = IT_UP;
  1052.       else
  1053.         {
  1054.           command = IT_L;
  1055.           ladderJump.set();
  1056.         }
  1057.       break;
  1058.     };
  1059.     break;
  1060.     
  1061.       case CO_UP:
  1062.     switch (stance) {
  1063.     case CO_center:
  1064.     case CO_air:
  1065.     case CO_dn:
  1066.     case CO_r:
  1067.     case CO_l:
  1068.     case CO_climb:
  1069.       if ((touching != CO_up) || canClimb || 
  1070.           (hanging.corner == CO_up_R) || (hanging.corner == CO_up_L))
  1071.         command = IT_UP;
  1072.       break;
  1073.     };
  1074.     break;
  1075.     
  1076.       case CO_UP_R:
  1077.     if (canClimb && touching != CO_up && ladderJump.ready())
  1078.       {
  1079.         command = IT_UP;
  1080.         break;
  1081.       }
  1082.     switch (stance) {
  1083.     case CO_center:
  1084.     case CO_dn:
  1085.     case CO_up:
  1086.       command = IT_R;
  1087.       break;
  1088.     case CO_r:
  1089.     case CO_l:
  1090.       command = IT_UP_R;
  1091.       break;
  1092.     case CO_climb:
  1093.       if (touching != CO_up)
  1094.         command = IT_UP;
  1095.       else
  1096.         {
  1097.           command = IT_R;
  1098.           ladderJump.set();
  1099.         }
  1100.       break;
  1101.     };
  1102.     break;
  1103.       }
  1104.       
  1105.       if ((command == IT_NO_COMMAND) && !canClimb)
  1106.     command = IT_CENTER;
  1107.     }
  1108.   
  1109.   if (command != IT_NO_COMMAND)
  1110.     {
  1111.       physical->set_command(command);
  1112.       return True;
  1113.     }
  1114.  
  1115.   return False;
  1116. }
  1117.  
  1118.  
  1119.  
  1120. Boolean Machine::has_gun(PhysicalP p)
  1121. {
  1122.   for (int n = 0; n < p->get_weapons_num(); n++)
  1123.     {
  1124.       PhysicalP gun = p->get_weapon(n);
  1125.       if (gun && gun->is_gun())
  1126.     return True;
  1127.     }
  1128.   return False;
  1129. }
  1130.  
  1131.  
  1132.  
  1133. Boolean Machine::has_cutter(PhysicalP p)
  1134. {
  1135.   for (int n = 0; n < p->get_weapons_num(); n++)
  1136.     {
  1137.       PhysicalP w = p->get_weapon(n);
  1138.       if (w && w->is_cutter())
  1139.     return True;
  1140.     }
  1141.   return False;
  1142. }
  1143.  
  1144.  
  1145.  
  1146. Boolean Machine::has_shield(PhysicalP p)
  1147. {
  1148.   for (int n = 0; n < p->get_items_num(); n++)
  1149.     {
  1150.       PhysicalP w = p->get_item(n);
  1151.       if (w && w->is_shield())
  1152.     return True;
  1153.     }
  1154.   return False;
  1155. }
  1156.  
  1157.  
  1158.  
  1159. Boolean Machine::has_item(PhysicalP p,ClassId classId)
  1160. {
  1161.   for (int n = 0; n < p->get_items_num(); n++)
  1162.     {
  1163.       PhysicalP item = p->get_item(n);
  1164.       if (item && item->get_class_id() == classId)
  1165.     return True;
  1166.     }
  1167.   return False;
  1168. }
  1169.  
  1170.  
  1171.  
  1172. Boolean Machine::weapon_current_is_gun(PhysicalP p)
  1173. {
  1174.   PhysicalP weapon = p->get_weapon_current();
  1175.   return weapon && weapon->is_gun();
  1176. }
  1177.  
  1178.  
  1179.  
  1180. Boolean Machine::weapon_current_is_cutter(PhysicalP p)
  1181. {
  1182.   PhysicalP weapon = p->get_weapon_current();
  1183.   return weapon && weapon->is_cutter();
  1184. }
  1185.  
  1186.  
  1187.  
  1188. PhysicalP Machine::new_target_id(Boolean &isEnemy,PhysicalP p,
  1189.                  PhysicalP masterP)
  1190. {
  1191.   LocatorP locator = get_locator();
  1192.   
  1193.   PhysicalP nearby[OL_NEARBY_MAX];
  1194.   int nearbyNum;
  1195.   locator->get_nearby(nearby,nearbyNum,p,TARGET_RANGE);
  1196.  
  1197.   PhysicalP items[OL_NEARBY_MAX];
  1198.   int itemsNum = 0;
  1199.   PhysicalP enemies[OL_NEARBY_MAX];
  1200.   int enemiesNum = 0;
  1201.  
  1202.  
  1203.   // Pull out possible items and enemies from nearby.
  1204.   const IntelOptions &ops = get_intel_options();
  1205.   ClassId classId = p->get_class_id();
  1206.   for (int n = 0; n < nearbyNum; n++)
  1207.     {
  1208.       IntelP intel = nearby[n]->get_intel();
  1209.       
  1210.       if (nearby[n] != masterP &&
  1211.       nearby[n]->is_creature() && 
  1212.       nearby[n]->alive() && 
  1213.       intel && 
  1214.       // Don't want to have slaves of same master fighting each other.
  1215.       !(masterSet && !intel->is_human() && 
  1216.         ((MachineP)intel)->masterSet && 
  1217.         ((MachineP)intel)->masterIntelId == masterIntelId) &&
  1218.       !(ops.ignoreLemmings && nearby[n]->get_class_id() == A_Lemming) &&
  1219.       (intel->is_human() ||
  1220.        !(ops.classFriends && nearby[n]->get_class_id() == classId)))
  1221.     {
  1222.       enemies[enemiesNum] = nearby[n];
  1223.       enemiesNum++;
  1224.     }
  1225.       else if (!ops.ignoreItems &&
  1226.            p->is_user() && 
  1227.            nearby[n]->is_item() && 
  1228.            ((ItemP)nearby[n])->can_take())
  1229.     {
  1230.       items[itemsNum] = nearby[n];
  1231.       itemsNum++;
  1232.     }
  1233.     }
  1234.  
  1235.   if (enemiesNum)
  1236.     {
  1237.       PhysicalP target = enemies[Utils::choose(enemiesNum)];
  1238.       targetId = target->get_id();
  1239.       isEnemy = True;
  1240.       return target;
  1241.     }
  1242.   
  1243.   if (itemsNum)
  1244.     {
  1245.       PhysicalP target = items[Utils::choose(itemsNum)];
  1246.       targetId = target->get_id();
  1247.       isEnemy = False;
  1248.       return target;
  1249.     }
  1250.  
  1251.   return NULL;
  1252. }
  1253.  
  1254.  
  1255.  
  1256. Boolean Enemy::is_enemy()
  1257. {
  1258.   return True;
  1259. }
  1260.  
  1261.  
  1262.  
  1263. Boolean Neutral::is_enemy()
  1264. {
  1265.   return False;
  1266. }
  1267.  
  1268.  
  1269.  
  1270. LemmingIntel::LemmingIntel(WorldP w,LocatorP l,char *name,const Id &home_id)
  1271. :Neutral(w,l,name,NULL,ITnone)
  1272. {
  1273.   Timer oTimer(LADDER_JUMP_TIME);
  1274.   ladderJump = oTimer;
  1275.   homeId = home_id;
  1276. }
  1277.  
  1278.  
  1279.  
  1280. Boolean LemmingIntel::is_lemming_intel()
  1281. {
  1282.   return True;
  1283. }
  1284.  
  1285.  
  1286.  
  1287. void LemmingIntel::clock(PhysicalP p)
  1288. {
  1289.   assert(alive() && p->is_creature());
  1290.   LocatorP l = get_locator();
  1291.  
  1292.   PhysicalP home = l->lookup(homeId);
  1293.   assert(home);
  1294.   const Area &area = home->get_area();
  1295.   Pos middle = area.get_middle();
  1296.  
  1297.   move_pos(p,middle,ladderJump);
  1298.   ladderJump.clock();
  1299.  
  1300.   // NOTE: Skipping Machine::clock.
  1301.   Intel::clock(p);
  1302. }
  1303.